﻿using DocumentFormat.OpenXml.Lite.Shared;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace DocumentFormat.OpenXml.Lite.Xml
{
    public class XmlList<T> : EventList<T>, IXmlSerializable
    {
        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            var r = reader.ReadSubtree();
            //r.Read();
            while (r.Read())
            {
                if (r.NodeType == XmlNodeType.Whitespace)
                    continue;

                object obj = null;
                if (typeof(T).IsInterface)
                {
                    Type type = null;
                    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
                    {
                        if (assembly.FullName.StartsWith("DocumentFormat"))
                        {
                            type = assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(T)))
                                .FirstOrDefault(
                                    f => f.GetCustomAttributes(typeof(XmlRootAttribute), false).Length > 0 &&
                                    (f.GetCustomAttributes(typeof(XmlRootAttribute), false)[0]
                                    as XmlRootAttribute).ElementName == reader.LocalName);

                            if (type != null)
                                break;
                        }
                    }

                    if (type != null)
                    {
                        obj = Activator.CreateInstance(type);
                        if (obj is XmlSerializable)
                        {
                            (obj as XmlSerializable).ReadXml(r);
                        }
                    }
                }
                else
                {
                    obj = Activator.CreateInstance(typeof(T));
                    if (obj is XmlSerializable)
                    {
                        (obj as XmlSerializable).ReadXml(r);
                    }
                }

                if (obj != null)
                {
                    this.Add((T)obj);
                }
            }
        }

        public void WriteXml(XmlWriter writer)
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add(string.Empty, string.Empty);

            foreach (var element in this)
            {
                var root = element.GetType().GetCustomAttributes(typeof(XmlRootAttribute), false)[0] as XmlRootAttribute;
                if (root.ElementName != string.Empty)
                {
                    writer.WriteStartElement(root.ElementName, root.Namespace);
                }
                else
                {
                    var obj = XmlSerializationContext.Instance.Trace.Last.Value;
                    var prop = obj.GetType().GetProperties().FirstOrDefault(p => p.GetValue(obj, new object[] { }) == this);
                    var xelement = prop.GetCustomAttributes(typeof(XmlElementAttribute), false)[0] as XmlElementAttribute;
                    writer.WriteStartElement(xelement.ElementName, xelement.Namespace);
                }
                (element as XmlSerializable).WriteXml(writer);
                writer.WriteEndElement();
            }
        }
    }
}
